package com.zondy.mapgis.psmap.manager.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zondy.mapgis.common.core.exception.ServiceException;
import com.zondy.mapgis.common.core.text.CharsetKit;
import com.zondy.mapgis.common.core.utils.JsonUtils;
import com.zondy.mapgis.common.core.utils.StringUtils;
import com.zondy.mapgis.common.core.utils.bean.BeanValidators;
import com.zondy.mapgis.common.core.utils.file.FileUploadUtils;
import com.zondy.mapgis.config.properties.FileProperties;
import com.zondy.mapgis.domain.psmap.AppTheme;
import com.zondy.mapgis.psmap.manager.mapper.AppThemeMapper;
import com.zondy.mapgis.psmap.manager.service.IAppThemeService;
import com.zondy.mapgis.psmap.manager.service.IAppWidgetService;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Validator;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class AppThemeServiceImpl extends ServiceImpl<AppThemeMapper, AppTheme> implements IAppThemeService {
   @Autowired
   private AppThemeMapper appThemeMapper;
   @Autowired
   private FileProperties fileProperties;
   @Autowired
   protected Validator validator;
   @Autowired
   private IAppWidgetService appWidgetService;
   private static final String[] THEME_FILE_RESOURCES = new String[]{"theme.js", "theme.css"};

   @Override
   public AppTheme selectAppThemeByThemeId(Long themeId) {
      return this.appThemeMapper.selectAppThemeByThemeId(themeId);
   }

   @Override
   public List<AppTheme> selectAppThemeList(AppTheme appTheme) {
      return this.appThemeMapper.selectAppThemeList(appTheme);
   }

   @Override
   public AppTheme selectAppThemeByThemeName(String themeName) {
      return this.appThemeMapper.selectAppThemeByThemeName(themeName);
   }

   @Override
   public boolean checkThemeNameUnique(String themeName) {
      int count = this.appThemeMapper.checkThemeNameUnique(themeName);
      return count <= 0;
   }

   @Override
   public int insertAppTheme(AppTheme appTheme) {
      return this.appThemeMapper.insertAppTheme(appTheme);
   }

   @Override
   public int updateAppTheme(AppTheme appTheme) {
      return this.appThemeMapper.updateAppTheme(appTheme);
   }

   @Override
   public int deleteAppThemeByThemeIds(Long[] themeIds) {
      return this.appThemeMapper.deleteAppThemeByThemeIds(themeIds);
   }

   @Override
   public int deleteAppThemeByThemeId(Long themeId) {
      return this.appThemeMapper.deleteAppThemeByThemeId(themeId);
   }

   @Override
   public byte[] exportThemes(List<AppTheme> appThemeList) {
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      ZipOutputStream zip = new ZipOutputStream(outputStream);
      Iterator var4 = appThemeList.iterator();

      while(var4.hasNext()) {
         AppTheme appTheme = (AppTheme)var4.next();
         this.exportTheme(appTheme, zip);
         this.exportThemeOtherResources(appTheme, zip);
      }

      IOUtils.closeQuietly(zip);
      return outputStream.toByteArray();
   }

   private void exportTheme(AppTheme appTheme, ZipOutputStream zip) {
      Map<String, String> themeBaseFileList = new HashMap<>();
      String folerName = appTheme.getThemeName();
      themeBaseFileList.put(folerName + "/manifest.json", appTheme.getManifest());
      themeBaseFileList.put(folerName + "/layout.json", appTheme.getLayout());
      themeBaseFileList.forEach((key, value) -> {
         StringWriter sw = new StringWriter();
         sw.append(value);

         try {
            zip.putNextEntry(new ZipEntry(key));
            IoUtil.writeUtf8(zip, false, sw.toString());
            IoUtil.close(sw);
            zip.flush();
            zip.closeEntry();
         } catch (IOException var7) {
            this.log.error("导出主题失败，主题名：" + folerName, var7);
         }

      });
   }

   private void exportThemeOtherResources(AppTheme appTheme, ZipOutputStream zip) {
      String folerName = appTheme.getThemeName();
      Map<String, File> fileResourceMap = this.appWidgetService.listFileResources("themes", folerName);
      fileResourceMap.keySet().forEach((filePath) -> {
         try {
            zip.putNextEntry(new ZipEntry(folerName + filePath));
            IoUtil.write(zip, false, FileUtil.readBytes(fileResourceMap.get(filePath)));
            zip.flush();
            zip.closeEntry();
         } catch (IOException var6) {
            this.log.error("导出主题失败，主题名：" + folerName, var6);
         }

      });
   }

   public List<AppTheme> parseThemesFromFile(MultipartFile file, boolean isUpdateSupport) throws IOException {
      if (file == null) {
         return null;
      } else {
         List<AppTheme> appThemeList = new ArrayList();
         String filePath = FileUploadUtils.upload(this.fileProperties.getFullDataPath(), file);
         File zipFile = FileUploadUtils.getAbsoluteFile(this.fileProperties.getFullDataPath(), filePath);
         File unzip = ZipUtil.unzip(zipFile, CharsetKit.CHARSET_GBK);
         File[] themeFolders = unzip.listFiles();
         if (themeFolders != null) {

             for (File themeFolder : themeFolders) {
                 AppTheme appTheme = new AppTheme();
                 String themeName = themeFolder.getName();
                 if (themeFolder.isDirectory()) {
                     File[] themeFiles = themeFolder.listFiles();
                     appTheme.setThemeName(themeName);
                     String themeIconBase64 = "";
                     if (themeFiles != null) {
                         int var17 = themeFiles.length;

                         for (int var18 = 0; var18 < var17; ++var18) {
                             File themeFile = themeFiles[var18];
                             String themeFileName = themeFile.getName();
                             if (themeFile.isFile()) {
                                 if (Arrays.asList(THEME_FILE_RESOURCES).contains(themeFileName)) {
                                     this.copyThemeFileResource(themeFile, themeName, themeFileName, isUpdateSupport);
                                 } else {
                                     String fileContent = FileUtil.readString(themeFile, Charset.forName("UTF-8"));
                                     if (themeFileName.equals("manifest.json")) {
                                         appTheme.setManifest(fileContent);
                                     }

                                     if (themeFileName.equals("layout.json")) {
                                         fileContent = fileContent.replace("\"/upload/", "\"/file/default/");
                                         appTheme.setLayout(fileContent);
                                     }
                                 }
                             } else if (themeFile.isDirectory() && themeFileName.equals("images")) {
                                 File[] var21 = themeFile.listFiles();

                                 for (File imageFile : var21) {
                                     String imageFileName = imageFile.getName();
                                     if (imageFileName.equals("icon.png")) {
                                         themeIconBase64 = Base64.getEncoder().encodeToString(FileUtil.readBytes(imageFile));
                                     } else if (!imageFileName.equals(".gitkeep")) {
                                         this.copyThemeFileResource(imageFile, themeName, "images" + File.separator + imageFileName, isUpdateSupport);
                                     }
                                 }
                             }
                         }
                     }

                     if (StringUtils.isNotEmpty(appTheme.getManifest()) && StringUtils.isNotEmpty(appTheme.getLayout())) {
                         Dict themeManifestDict = JsonUtils.parseMap(appTheme.getManifest());
                         if (StringUtils.isNull(themeManifestDict.get("icon")) && StringUtils.isNotEmpty(themeIconBase64)) {
                             themeManifestDict.put("icon", "data:image/png;base64," + themeIconBase64);
                             appTheme.setManifest(JsonUtils.toJsonString(themeManifestDict));
                         }

                         appThemeList.add(appTheme);
                     }
                 }
             }
         }

         FileUtil.del(zipFile);
         FileUtil.del(unzip);
         return appThemeList;
      }
   }

   @Override
   public String importThemes(List<AppTheme> appThemeList, boolean isUpdateSupport, String operName) {
      if (!StringUtils.isNull(appThemeList) && !appThemeList.isEmpty()) {
         int successNum = 0;
         int failureNum = 0;
         StringBuilder successMsg = new StringBuilder();
         StringBuilder failureMsg = new StringBuilder();

          for (AppTheme appTheme : appThemeList) {
              try {
                  AppTheme t = this.appThemeMapper.selectAppThemeByThemeName(appTheme.getThemeName());
                  if (StringUtils.isNull(t)) {
                      BeanValidators.validateWithException(this.validator, appTheme, new Class[0]);
                      appTheme.setCreateBy(operName);
                      this.insertAppTheme(appTheme);
                      ++successNum;
                      successMsg.append("<br/>" + successNum + "、主题 " + appTheme.getThemeName() + " 导入成功");
                  } else if (isUpdateSupport) {
                      BeanValidators.validateWithException(this.validator, appTheme, new Class[0]);
                      appTheme.setThemeId(t.getThemeId());
                      appTheme.setUpdateBy(operName);
                      this.updateAppTheme(appTheme);
                      ++successNum;
                      successMsg.append("<br/>" + successNum + "、主题 " + appTheme.getThemeName() + " 更新成功");
                  } else {
                      ++failureNum;
                      failureMsg.append("<br/>" + failureNum + "、主题 " + appTheme.getThemeName() + " 已存在");
                  }
              } catch (Exception var12) {
                  ++failureNum;
                  String msg = "<br/>" + failureNum + "、主题 " + appTheme.getThemeName() + " 导入失败：";
                  failureMsg.append(msg + var12.getMessage());
                  this.log.error(msg, var12);
              }
          }

         if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
         } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
            return successMsg.toString();
         }
      } else {
         throw new ServiceException("导入主题数据不能为空！");
      }
   }

   private void copyThemeFileResource(File themeFile, String themeName, String resourceName, boolean isUpdateSupport) {
      String fileFullPath = this.fileProperties.getFullDataPath() + File.separator + "themes" + File.separator + themeName + File.separator + resourceName;
      File copyFile = new File(fileFullPath);
      if (!copyFile.exists()) {
         FileUtil.copyContent(themeFile, copyFile, true);
      } else if (isUpdateSupport) {
         FileUtil.copyContent(themeFile, copyFile, true);
      }

   }
}
